package com.androidhelper.module.common.http;

import com.androidhelper.module.common.BuildConfig;
import com.androidhelper.module.common.http.cert.TrustAllCerts;
import com.androidhelper.module.common.http.cert.TrustAllHostnameVerifier;
import com.androidhelper.module.common.http.cookie.CookieManager;
import com.androidhelper.module.common.http.interceptor.CacheInterceptor;
import com.androidhelper.module.common.http.interceptor.CustomDynamicInterceptor;
import com.androidhelper.module.common.http.interceptor.CustomLoggerInterceptor;
import com.androidhelper.module.common.http.interceptor.HeaderInterceptor;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.FieldNamingStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.File;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import okhttp3.Cache;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;


public class HttpClient {

    private Retrofit mRetrofit;



    // 延迟加载、按需创建
    public static HttpClient getInstance() {
        return RetrofitHttpClientHolder.INSTANCE;
    }

    // 1. 创建静态内部类
    private static   class RetrofitHttpClientHolder {
        // 在静态内部类里创建单例
        private static   HttpClient INSTANCE = new HttpClient();
    }

    private HttpClient() { createRetrofit();}



    /*
     * createRetrofit
     *
     * */
    private Retrofit createRetrofit() {
         //只对retrofit 进行单利
         if(mRetrofit == null){
             mRetrofit = new Retrofit.Builder()
                       .baseUrl(UrlTools.BASE_URL)
                       .client(createOkHttpClient())
                      .addConverterFactory(GsonConverterFactory.create(getJson()))
                    // .addConverterFactory(GsonDConverterFactory.create())
                      .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                      .build();
         }

        return mRetrofit;
    }


    Gson gson;
    private Gson getJson() {
        if(gson == null){
            GsonBuilder builder = new GsonBuilder();
            builder.setLenient();
            builder.setFieldNamingStrategy(new AnnotateNaming()).setDateFormat("yyyy-MM-dd HH:mm:ss");
            builder.serializeNulls();
            gson = builder.create();
        }
        return gson;
    }


    //  private OkHttpClient mOkHttpClient;
    private static final long DEFAULT_TIME_OUT = 30;
    /**
     * 配置OKHttpClient
     */
    private OkHttpClient createOkHttpClient() {
        OkHttpClient.Builder builder  = new OkHttpClient.Builder();
        if (BuildConfig.DEBUG){
            builder.addInterceptor(new HeaderInterceptor())//设置Http请求头。给OkHttp 添加请求头拦截器，配置请求头信息
                    .addInterceptor(new CustomLoggerInterceptor()); //如果是测试包  设置日志拦截器，拦截服务器返回的json数据
        }




        // 为OkHttp配置缓存  添加缓存最大的内存,默认为100M
        File cacheFile = new File( "OkHttpCache");
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100);
        builder.cache(cache); // 添加缓存
        builder.addInterceptor(new CacheInterceptor());
        builder.addNetworkInterceptor(new CacheInterceptor());



          builder
                     //  https，我们还可以在此处理证书校验以及服务器校验。
                  .sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts())// 创建一个证书对象
                    .hostnameVerifier(new TrustAllHostnameVerifier()) // 校验名称,这个对象就是信任所有的主机,也就是信任所有https的请求  OK
                    .cookieJar(CookieManager.getInstance()) //  MaoWanAndroidClient
                  //设置超时时间
                .connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);//错误重连



        addCustomDynamicInterceptor(builder);//设置动态参数添加拦截器
         // addExpiredInterceptor(builder); //请求失效校验拦截器

        OkHttpClient mOkHttpClient = builder.build();
        return mOkHttpClient;
    }




    /*
    * 有时候，我们需要对所有请求添加一些固定的请求参数，但是这些参数的值又是变化的，
    * 这个时候我们就需要动态添加请求参数【例如，请求的token、时间戳以及签名等】
    *
    * */
    private void addCustomDynamicInterceptor(OkHttpClient.Builder builder) {
        builder.addInterceptor(new CustomDynamicInterceptor());
    }


    private void addExpiredInterceptor(OkHttpClient.Builder builder) {
       // builder.addInterceptor(new CustomExpiredInterceptor());
    }





    /**
     * 实现 HTTPS 请求
     */
    private SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory sslSocketFactory = null;
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslSocketFactory;
    }






    private static class AnnotateNaming implements FieldNamingStrategy {
        @Override
        public String translateName(Field field) {
            ParamNames a = field.getAnnotation(ParamNames.class);
            return a != null ? a.value() : FieldNamingPolicy.IDENTITY.translateName(field);
        }
    }



    /**
     * 接口定义类,获取到可以缓存的retrofit
     *
     * @param tClass
     * @param <T>
     * @return
     */
  /*  public  <T>T getApiService(Class<T> tClass) {
        return getRetrofit().create(tClass);
    }*/


  public Retrofit getRetrofit(){
      return  mRetrofit;
  }




    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @interface ParamNames {
        String value();
    }

}



























